home *** CD-ROM | disk | FTP | other *** search
/ Nautilus 1992 July / Nautilus-3-8 / Nautilus-3-8.bin / Tools & Utilities / Hacks Pt.1 ƒ / 3D Bouncing Ball AD Module / 3DBouncingBall.p < prev    next >
Encoding:
Text File  |  1992-06-18  |  15.1 KB  |  559 lines

  1. {3D Bouncing Ball Module}
  2. {Written by Daniel C. Stegman, Exodus Software}
  3. {⌐1992, Exodus Software, All Rights Reserved.}
  4. {This code is intended for use as a After Dark 2.0 ScreenSaver Module.  It is intended for entertainment}
  5. {use, and for the enlightenment of programmers.  It uses fixed math to optimize all of it's 3D calculations,}
  6. {and uses Color on those macs that can support it.  Enjoy!!}
  7. {Dedicated to the Hackers of MacHack, 1992}
  8.  
  9. unit GraphicsDemo;
  10.  
  11. interface
  12.  
  13.     uses
  14.         MemTypes, Memory, Packages, FixMath, Quickdraw, Sound, ToolIntf, GraphicsModuleTypes, FixedThreeDeeCalls;
  15.  
  16. CONST
  17.     kRedColor            = 1;
  18.     kBlueColor        = 2;
  19.     kGreenColor        = 3;
  20.     kPurpleColor        = 4;
  21.     kYellowColor    = 5;
  22.     kOrangeColor    = 6;
  23.     kWhiteColor        = 7;
  24.  
  25. TYPE
  26.     rectArray = array [1..10] of rect;
  27.     theBall = RECORD
  28.         its3DLoc        : ThreeDeePoint;
  29.         itsShadow        : ThreeDeePoint;
  30.         its2DLoc        : point;
  31.         sh2DLoc        : point;
  32.         oldRect            : rect;
  33.         Old2DRects    : rectArray;
  34.         Oldsh2DRects: rectArray;
  35.         bounceCount    : integer;
  36.         xVector        : fixed;
  37.         yVector        : fixed;
  38.         zVector        : fixed;
  39.         itsColor        : RGBColor;
  40.         colorCode        : integer;
  41.         gravity            : integer;
  42.         speed            : integer;
  43.         shadowVis    : boolean;
  44.     end;
  45.     
  46.     ballArray = array[1..5] of theBall;
  47.     
  48.     tempStorage = RECORD
  49.         aBall                : theBall;
  50.         bBall                : theBall;
  51.         cBall                : theBall;
  52.         dBall                : theBall;
  53.         eBall                : theBall;
  54.         doColor            : boolean;
  55.         forceGray        : boolean;
  56.         kWhiteRGB    : RGBColor;
  57.         kGrayRGB        : RGBColor;
  58.         kBlackRGB    : RGBColor;
  59.         RotaryColor    : integer;
  60.         numballs        : integer;
  61.         theBalls        : ballArray;
  62.         aBox                : ThreeDeeWorld;
  63.     end;
  64.     tempPtr    = ^tempStorage;
  65.     tempHdl    = ^tempPtr;
  66.     
  67. {    integerPtr            = ^integer;    }
  68.     integerHandle        = ^integerPtr;
  69.     booleanPtr            = ^boolean;
  70.     booleanHandle        = ^booleanPtr;
  71.  
  72.     function DoInitialize (var storage: Handle; blankRgn: rgnHandle; params: GMParamBlockPtr): OSErr;
  73.     function DoBlank (storage: Handle; blankRgn: rgnHandle; params: GMParamBlockPtr): OSErr;
  74.     function DoDrawFrame (storage: Handle; blankRgn: rgnHandle; params: GMParamBlockPtr): OSErr;
  75.     function DoClose (storage: Handle; blankRgn: RgnHandle; params: GMParamBlockPtr): OSErr;
  76.     function DoSetup (blankRgn: rgnHandle; message: integer; params: GMParamBlockPtr): OSErr;
  77.  
  78. IMPLEMENTATION
  79.  
  80. PROCEDURE InitializeArray(VAR itsRectArray : rectArray);
  81.     VAR
  82.         count        : integer;
  83. BEGIN
  84.     For count := 1 to 10
  85.         do SetRect(itsRectArray[count], 1, 1, 1, 1);
  86. END;
  87.  
  88. PROCEDURE ShiftArray(VAR itsRectArray : rectArray); 
  89.     VAR
  90.         count        : integer;
  91. BEGIN
  92.     For count := 9 downto 1
  93.         do itsRectArray[count + 1] := itsRectArray[count];
  94. END;
  95.  
  96. PROCEDURE InitBall(var ballA : theBall; boxA : ThreeDeeWorld; doColor, forceGray : boolean; params: GMParamBlockPtr);
  97.     VAR
  98.         two                : fixed;
  99.         eightTenths    : fixed;
  100.         tempFixed        : fixed;
  101.         newColor        : integer;
  102.         
  103.     FUNCTION ReturnMagicColor(tempValue : integer): RGBColor;
  104.         VAR
  105.             tempColor        : RGBColor;
  106.             newColor        : integer;
  107.     BEGIN
  108.         tempColor.red := 0;
  109.         tempColor.green := 0;
  110.         tempColor.blue := 0;
  111.         case tempValue of
  112.             kRedColor:
  113.                 begin
  114.                     tempColor.red := -1;
  115.                 end;
  116.             kBlueColor:
  117.                 begin
  118.                     tempColor.blue := -1;
  119.                 end;
  120.             kGreenColor:
  121.                 begin
  122.                     tempColor.green := -1;
  123.                 end;
  124.             kPurpleColor:
  125.                 begin
  126.                     tempColor.red := -1;
  127.                     tempColor.blue := -1;
  128.                 end;
  129.             kYellowColor:
  130.                 begin
  131.                     tempColor.red := -1;
  132.                     tempColor.green := -1;
  133.                 end;
  134.             kOrangeColor:
  135.                 begin
  136.                     tempColor.red := -1;
  137.                     tempColor.green := 32767;
  138.                 end;    
  139.             otherwise
  140.                 begin
  141.                     tempColor.red := -1;
  142.                     tempColor.blue := -1;
  143.                     tempColor.green := -1;
  144.                 end;
  145.         end;
  146.         ReturnMagicColor := tempColor;
  147.     END;
  148. BEGIN
  149.     with ballA, boxA do begin
  150.         two := Long2Fix(2);
  151.         eightTenths := X2Fix(0.8);
  152.  
  153.         with params^ do begin
  154.             gravity := controlValues[0];
  155.             speed := controlValues[1] + 1;
  156.             shadowVis := (controlValues[3] <> 0);
  157.         end;
  158.  
  159.     {    gravity := 20;
  160.         speed := 40;
  161.         shadowVis := TRUE;    }
  162.         tempFixed := frontTopRight.x - frontTopLeft.x;
  163.         
  164.         its3DLoc.x := FixDiv(tempFixed, two);
  165.         its3DLoc.y := frontTopLeft.y;
  166.         its3DLoc.z := its3DLoc.x;
  167.         xVector := Long2Fix(random mod speed);
  168.         yVector := Long2Fix(abs(random mod speed));
  169.         zVector := Long2Fix(random mod speed);        
  170.         IF doColor
  171.             THEN BEGIN
  172.                 IF forceGray
  173.                     THEN newColor := kWhiteColor
  174.                     ELSE newColor := random mod 7;
  175.                 itsColor := ReturnMagicColor(newColor);
  176.                 colorCode := newColor;
  177.             END;
  178.         {    Cannon Settings    }
  179.     {    its3DLoc.x := FixDiv(tempFixed, two);
  180.         its3DLoc.y := FixMul((frontBotLeft.y - frontTopLeft.y), eightTenths);
  181.         its3DLoc.z := frontBotLeft.z;
  182.         xVector := Long2Fix(random mod speed);
  183.         yVector := Long2Fix(- abs(random mod 30));
  184.         zVector := Long2Fix(40 + abs(random mod 30));    }
  185.         
  186.         bounceCount := 0;
  187.     end;
  188. END;
  189.  
  190. FUNCTION DoInitialize (var storage: Handle; blankRgn: rgnHandle; params: GMParamBlockPtr): OSErr;
  191.     {Allocate memory and initialize variables here}
  192.     VAR
  193.         index    : integer;
  194.         aHdl        : tempHdl;
  195.         bHdl        : Handle;
  196.         aRect    : rect;
  197.         two        : fixed;
  198.         tempFixed    : fixed;
  199. BEGIN
  200.     aHdl := tempHdl(NewHandle(sizeof(tempStorage)));
  201.     if aHdl <> nil
  202.         then begin
  203.             aRect := params^.monitors^.monitorList[0].bounds;
  204.             SetupThreeDeeWorld (aHdl^^.aBox, aRect);
  205.             
  206.             with aHdl^^, aBall, aBox do begin
  207.                 doColor := (params^.colorQDAvail) and (params^.monitors^.monitorList[0].curDepth > 2);
  208.                 forceGray := params^.monitors^.monitorList[0].curDepth = 4;
  209.                 numballs := (params^.controlValues[2] div 20) + 1;
  210.                 IF numBalls > 5
  211.                     THEN numBalls := 5;
  212.  
  213.                 kWhiteRGB.red := -1;
  214.                 kWhiteRGB.green := -1;
  215.                 kWhiteRGB.blue := -1;
  216.                 kGrayRGB.red := 32767;
  217.                 kGrayRGB.green := 32767;
  218.                 kGrayRGB.blue := 32767;
  219.                 kBlackRGB.red := 0;
  220.                 kBlackRGB.green := 0;
  221.                 kBlackRGB.blue := 0;
  222.                 
  223.                 RotaryColor := 1;
  224.                 
  225.                 For index := 1 to numBalls
  226.                     do begin
  227.                         InitializeArray(theBalls[index].Old2DRects);
  228.                         InitializeArray(theBalls[index].OldSH2DRects);
  229.                         InitBall(theBalls[index], aBox, doColor, forceGray, params);
  230.                         RotaryColor := RotaryColor + 1;
  231.                     end;
  232.                     
  233.                 FillRect(aBox.screenRect, params^.qdGlobalsCopy^.qdBlack);
  234.             end;
  235.             storage := handle(aHdl);
  236.             DoInitialize := noErr;
  237.         end
  238.     else DoInitialize := MemError;
  239. END;
  240.  
  241. FUNCTION DoBlank (storage: Handle; blankRgn: rgnHandle; params: GMParamBlockPtr): OSErr;
  242.     {Blank the screen.  You could also have "credits" appear on the screen here}
  243. BEGIN
  244.     FillRgn(blankRgn, params^.qdGlobalsCopy^.qdBlack);
  245.     DoBlank := noErr;
  246. END;
  247.  
  248. FUNCTION MoveBall (var ballA : theBall; boxA : ThreeDeeWorld; doColor, forceGray : boolean; params: GMParamBlockPtr): boolean;
  249.     VAR
  250.         tempFixed    : fixed;
  251.         two            : fixed;
  252.         anErr        : OSErr;
  253. BEGIN
  254.     with ballA, boxA do begin
  255.         { Update the location by applying the vectors }
  256.         its3DLoc.x := its3DLoc.x + xVector;
  257.         its3DLoc.y := its3DLoc.y + yVector;
  258.         its3DLoc.z := its3DLoc.z + zVector;
  259.         yVector := yVector + X2Fix(gravity / 20);
  260.         
  261.         {    Check for out of bounds    }
  262.         IF (its3DLoc.x <= frontTopLeft.x)
  263.             THEN BEGIN
  264.                 its3DLoc.x := frontTopLeft.x;
  265.                 xVector := -xVector;
  266.             END
  267.         ELSE IF (its3DLoc.x >= frontTopRight.x)
  268.             THEN BEGIN
  269.                 its3DLoc.x := frontTopRight.x;
  270.                 xVector := -xVector;
  271.             END;
  272.             
  273.         IF (its3DLoc.y <= frontTopLeft.y)
  274.             THEN BEGIN
  275.                 its3DLoc.y := frontTopLeft.y;
  276.                 yVector := -yVector;
  277.             END
  278.         ELSE IF (its3DLoc.y >= frontBotLeft.y)
  279.             THEN BEGIN
  280.                 its3DLoc.y := frontBotLeft.y;
  281.                 IF gravity > 0
  282.                     THEN BEGIN
  283.                         yVector := FixMul(-yVector, X2Fix(2/3));
  284.                         xVector := FixMul(xVector, X2Fix(3/4));
  285.                         zVector := FixMul(zVector, X2Fix(3/4));        
  286.                     END
  287.                     ELSE BEGIN
  288.                         yVector := -yVector;
  289.                     END;
  290.                 bounceCount := bounceCount + 1;
  291.                 IF (bounceCount = 8)
  292.                     THEN BEGIN
  293.                         InitBall(ballA, boxA, doColor, forceGray, params);
  294.                     END;    
  295.             END;
  296.             
  297.         IF (its3DLoc.z <= frontTopLeft.z)
  298.             THEN BEGIN
  299.                 its3DLoc.z := frontTopLeft.z;
  300.                 zVector := -zVector;
  301.             END
  302.         ELSE IF (its3DLoc.z >= backTopRight.z)
  303.             THEN BEGIN
  304.                 its3DLoc.z := backTopRight.z;
  305.                 zVector := -zVector;
  306.             END;    
  307.     end;    
  308. END;
  309.  
  310. PROCEDURE DrawBox (boxA : ThreeDeeWorld; kWhiteRGB, kGrayRGB, kBlackRGB : RGBColor; params : GMParamBlockPtr);
  311.     VAR
  312.         itsRect                : rect;
  313.         tempPt1            : point;
  314.         tempPt2            : point;
  315. BEGIN
  316.     with boxA do begin    
  317.         IF params^.colorQDAvail
  318.             THEN RGBForeColor(kGrayRGB)
  319.             ELSE PenPat(params^.qdGlobalsCopy^.qdWhite);
  320.             
  321.         ThreeDeeToTwoDee(boxA, frontTopLeft, tempPt1);
  322.         ThreeDeeToTwoDee(boxA, frontBotRight, tempPt2);
  323.         SetRect(itsRect, tempPt1.h, tempPt1.v, tempPt2.h, tempPt2.v);
  324.         FrameRect (itsRect);
  325.         ThreeDeeToTwoDee(boxA, backTopLeft, tempPt1);
  326.         ThreeDeeToTwoDee(boxA, BackBotRight, tempPt2);
  327.         SetRect(itsRect, tempPt1.h, tempPt1.v, tempPt2.h, tempPt2.v);
  328.         FrameRect (itsRect);
  329.         ThreeDeeToTwoDee(boxA, frontTopLeft, tempPt1);
  330.         MoveTo (tempPt1.h, tempPt1.v);
  331.         ThreeDeeToTwoDee(boxA, backTopLeft, tempPt1);
  332.         LineTo (tempPt1.h, tempPt1.v);
  333.         ThreeDeeToTwoDee(boxA, frontTopRight, tempPt1);
  334.         MoveTo (tempPt1.h, tempPt1.v);
  335.         ThreeDeeToTwoDee(boxA, backTopRight, tempPt1);
  336.         LineTo (tempPt1.h, tempPt1.v);
  337.         ThreeDeeToTwoDee(boxA, frontBotLeft, tempPt1);
  338.         MoveTo (tempPt1.h, tempPt1.v);
  339.         ThreeDeeToTwoDee(boxA, backBotLeft, tempPt1);
  340.         LineTo (tempPt1.h, tempPt1.v);
  341.         ThreeDeeToTwoDee(boxA, frontBotRight, tempPt1);
  342.         MoveTo (tempPt1.h, tempPt1.v);
  343.         ThreeDeeToTwoDee(boxA, backBotRight, tempPt1);
  344.         LineTo (tempPt1.h, tempPt1.v);
  345.         IF params^.colorQDAvail
  346.             THEN RGBForeColor(kWhiteRGB);
  347.     end;
  348. END;
  349.  
  350. PROCEDURE UpdateBall (VAR ballA : theBall; aBox : ThreeDeeWorld; kWhiteRGB, kGrayRGB, kBlackRGB : RGBColor; params : GMParamBlockPtr);
  351.     VAR
  352.         itsSize        : integer;
  353.         zDepth        : fixed;
  354.         itsScale    : fixed;
  355.         itsRect        : rect;
  356.         shRect        : rect;
  357.         tempString1    : Str255;
  358.         tempString2    : Str255;
  359.         
  360.     PROCEDURE RampDownColor(tempColor : RGBColor; colorCode, degradeBy : integer);
  361.         VAR
  362.             degradeVal        : integer;
  363.     BEGIN
  364.     {    degradeVal := trunc(65000 / (1.0 * degradeBy));    }
  365.         degradeVal := 65000 div degradeBy;
  366.         IF params^.colorQDAvail
  367.             THEN BEGIN
  368.                 Case colorCode of
  369.                     kRedColor:
  370.                         begin
  371.                             tempColor.red := degradeVal;
  372.                         end;
  373.                     kBlueColor:
  374.                         begin
  375.                             tempColor.blue := degradeVal;
  376.                         end;
  377.                     kGreenColor:
  378.                         begin
  379.                             tempColor.green := degradeVal;
  380.                         end;
  381.                     kPurpleColor:
  382.                         begin
  383.                             tempColor.red := degradeVal;
  384.                             tempColor.blue := degradeVal;
  385.                         end;
  386.                     kYellowColor:
  387.                         begin
  388.                             tempColor.red := degradeVal;
  389.                             tempColor.green := degradeVal;
  390.                         end;
  391.                     kOrangeColor:
  392.                         begin
  393.                             tempColor.red := degradeVal;
  394.                             tempColor.green := degradeVal;            { Make it yellow since Orange fades fast }
  395.                         end;    
  396.                     otherwise
  397.                         begin
  398.                             tempColor.red := degradeVal;
  399.                             tempColor.blue := degradeVal;
  400.                             tempColor.green := degradeVal;
  401.                         end;
  402.                 end;
  403.                 RGBForeColor(tempColor);
  404.             END
  405.             ELSE BEGIN
  406.                 CASE degradeBy of
  407.                     1:
  408.                         PenPat(params^.qdGlobalsCopy^.qdWhite);
  409.                     2..4:
  410.                         PenPat(params^.qdGlobalsCopy^.qdLtGray);
  411.                     5..7:
  412.                         PenPat(params^.qdGlobalsCopy^.qdGray);
  413.                     otherwise
  414.                         PenPat(params^.qdGlobalsCopy^.qdDkGray);
  415.                 end;
  416.             END;
  417.     END;
  418. BEGIN
  419.     zDepth := abs(aBox.frontTopLeft.z - aBox.backTopLeft.z);
  420.     itsScale := FixDiv((aBox.backTopLeft.z - ballA.its3DLoc.z), aBox.backTopLeft.z);
  421.     itsSize := 4 + Fix2Long(FixMul(itsScale, Long2Fix(20)));
  422.     
  423.     itsRect.left := ballA.its2DLoc.h - (itsSize div 2);
  424.     itsRect.right := ballA.its2DLoc.h + (itsSize div 2);
  425.     itsRect.top := ballA.its2DLoc.v - (itsSize div 2);
  426.     itsRect.bottom := ballA.its2DLoc.v + (itsSize div 2);
  427.     IF ballA.shadowVis
  428.         THEN BEGIN
  429.             shRect.left := ballA.sh2DLoc.h - (itsSize div 2);
  430.             shRect.right := ballA.sh2DLoc.h + (itsSize div 2);
  431.             shRect.top := ballA.sh2DLoc.v - (itsSize div 4);
  432.             shRect.bottom := ballA.sh2DLoc.v + (itsSize div 4);    
  433.         END;
  434.  
  435.     IF params^.colorQDAvail
  436.         THEN BEGIN
  437.             RGBForeColor(kWhiteRGB);
  438.         END
  439.         ELSE BEGIN
  440.             PenPat(params^.qdGlobalsCopy^.qdWhite);
  441.         END;
  442.  
  443.     with ballA do begin
  444.     IF params^.colorQDAvail
  445.         THEN BEGIN
  446.             RGBForeColor(kBlackRGB);
  447.             PaintOval(Old2DRects[10]);
  448.             PaintOval(Old2DRects[1]);        
  449.             IF shadowVis
  450.                 THEN PaintOval(OldSh2DRects[10]);
  451.         END
  452.         ELSE BEGIN
  453.             FillOval(Old2DRects[10], params^.qdGlobalsCopy^.qdBlack);
  454.             FillOval(Old2DRects[1], params^.qdGlobalsCopy^.qdBlack);        
  455.             IF shadowVis
  456.                 THEN FillOval(OldSh2DRects[10], params^.qdGlobalsCopy^.qdBlack);
  457.         END;
  458.  
  459.         ShiftArray(Old2DRects);
  460.         Old2DRects[1] := itsRect;    
  461.         ShiftArray(OldSh2DRects);
  462.         OldSh2DRects[1] := shRect;
  463.         
  464.         RampDownColor(itsColor, colorCode, 10);
  465.         FrameOval(Old2DRects[10]);
  466.         RampDownColor(itsColor, colorCode, 9);
  467.         FrameOval(Old2DRects[9]);
  468.         RampDownColor(itsColor, colorCode, 8);
  469.         FrameOval(Old2DRects[8]);    
  470.         RampDownColor(itsColor, colorCode, 7);
  471.         FrameOval(Old2DRects[7]);
  472.         RampDownColor(itsColor, colorCode, 6);
  473.         FrameOval(Old2DRects[6]);
  474.         RampDownColor(itsColor, colorCode, 5);
  475.         FrameOval(Old2DRects[5]);
  476.         RampDownColor(itsColor, colorCode, 4);
  477.         FrameOval(Old2DRects[4]);
  478.         RampDownColor(itsColor, colorCode, 3);
  479.         FrameOval(Old2DRects[3]);
  480.         RampDownColor(itsColor, colorCode, 2);
  481.         FrameOval(Old2DRects[2]);
  482.         IF params^.colorQDAvail
  483.             THEN RGBForeColor(itsColor)
  484.             ELSE PenPat(params^.qdGlobalsCopy^.qdWhite);
  485.         PaintOval(Old2DRects[1]);
  486.         
  487.         IF shadowVis
  488.             THEN BEGIN
  489.                 RampDownColor(itsColor, colorCode, 10);
  490.                 FrameOval(OldSh2DRects[10]);
  491.                 RampDownColor(itsColor, colorCode, 9);
  492.                 FrameOval(OldSh2DRects[9]);
  493.                 RampDownColor(itsColor, colorCode, 8);
  494.                 FrameOval(OldSh2DRects[8]);    
  495.                 RampDownColor(itsColor, colorCode, 7);
  496.                 FrameOval(OldSh2DRects[7]);
  497.                 RampDownColor(itsColor, colorCode, 6);
  498.                 FrameOval(OldSh2DRects[6]);
  499.                 RampDownColor(itsColor, colorCode, 5);
  500.                 FrameOval(OldSh2DRects[5]);
  501.                 RampDownColor(itsColor, colorCode, 4);
  502.                 FrameOval(OldSh2DRects[4]);
  503.                 RampDownColor(itsColor, colorCode, 3);
  504.                 FrameOval(OldSh2DRects[3]);
  505.                 RampDownColor(itsColor, colorCode, 2);
  506.                 FrameOval(OldSh2DRects[2]);
  507.                 IF params^.colorQDAvail
  508.                     THEN RGBForeColor(itsColor)
  509.                     ELSE PenPat(params^.qdGlobalsCopy^.qdWhite);
  510.                 FrameOval(OldSh2DRects[1]);
  511.             END;
  512.     end;
  513. END;
  514.  
  515. FUNCTION DoDrawFrame (storage: Handle; blankRgn: rgnHandle; params: GMParamBlockPtr): OSErr;
  516.     {This function is repeatedly called by After Dark.  This is where the main drawing is done.}
  517.     VAR
  518.         aHdl            : tempHdl;
  519.         movement    : boolean;
  520.         index        : integer;
  521.         waited        : longint;
  522. BEGIN
  523.     aHdl := tempHdl(storage);
  524.     with aHdl^^ do begin
  525.         
  526.         For index := 1 to numBalls
  527.             do begin
  528.                 movement := MoveBall(theBalls[index], aBox, doColor, forceGray, params);
  529.                 ThreeDeeToTwoDee(aBox, theBalls[index].its3DLoc, theBalls[index].its2DLoc);
  530.                 theBalls[index].itsShadow := theBalls[index].its3DLoc;
  531.                 theBalls[index].itsShadow.y := aBox.frontBotRight.y;
  532.                 ThreeDeeToTwoDee(aBox, theBalls[index].itsShadow, theBalls[index].sh2DLoc);        
  533.                 UpdateBall(theBalls[index], aBox, kWhiteRGB, kGrayRGB, kBlackRGB, params);        
  534.             end;
  535.         
  536.         DrawBox (aBox, kWhiteRGB, kGrayRGB, kBlackRGB, params);            
  537.     end;
  538.     DoDrawFrame := noErr;
  539. END;
  540.  
  541. FUNCTION DoClose (storage: Handle; blankRgn: RgnHandle; params: GMParamBlockPtr): OSErr;
  542.     {Deallocate your memory here.  You can also put something on the screen.}
  543. BEGIN
  544.     IF params^.colorQDAvail
  545.         THEN BEGIN
  546.             RGBForeColor(tempHdl(storage)^^.kWhiteRGB);
  547.             RGBBackColor(tempHdl(storage)^^.kBlackRGB);
  548.         END;
  549.     DisposHandle(storage);
  550.     DoClose := noErr;
  551. END;
  552.  
  553. FUNCTION DoSetup (blankRgn: rgnHandle; message: integer; params: GMParamBlockPtr): OSErr;
  554.     {This is called when the user clicks on a button in the Control Panel.}
  555. BEGIN
  556.     DoSetup := noErr;
  557. END;
  558.  
  559. END.